import websocket
import json
import requests
import threading
import ssl
import time
import redis
from datetime import datetime
import itertools
from collections import OrderedDict
from collections import defaultdict

pool = redis.ConnectionPool(host='localhost',port=6379, db=1)
r = redis.Redis(connection_pool=pool)

#递减排序
def sorted_ordered_dict_reverse(data):
    return OrderedDict(sorted(data.items(), key=lambda x: x[0], reverse=True))

#递增排序
def sorted_ordered_dict(data):
    return OrderedDict(sorted(data.items(), key=lambda x: x[0]))


# 全局变量，保存本地的订单簿副本
orderbook = {
    "bids": {},  # 存储买单
    "asks": {}   # 存储卖单
}

# 用于同步访问 orderbook 的锁
lock = threading.Lock()

def get_initial_orderbook(symbol):
    global orderbook
    url = f"https://fapi.binance.com/fapi/v1/depth?symbol={symbol}&limit=1000"
    response = requests.get(url)
    data = response.json()

    # with lock:
    orderbook["bids"] = {float(price): float(quantity) for price, quantity in data["bids"]}
    orderbook["asks"] = {float(price): float(quantity) for price, quantity in data["asks"]}
    
    return data["lastUpdateId"]

def on_message(ws, message):
    message = json.loads(message)
    event = message["data"]
    u = event["u"]
    U = event["U"]
    pu = event["pu"]

    #with lock:
        # 确保事件的顺序是正确的
    if pu != orderbook.get("lastUpdateId", 0):
        print("Event out of sync, reinitializing orderbook...")
        initialize_orderbook("BTCUSDT")
        return

    # 更新订单簿副本
    for bid in event["b"]:
        price = float(bid[0])
        quantity = float(bid[1])
        if quantity == 0:
            
            if price in orderbook["bids"]:
                del orderbook["bids"][price]
                print(price)
        else:
            orderbook["bids"][price] = quantity
    for ask in event["a"]:
        price = float(ask[0])
        quantity = float(ask[1])

        if quantity == 0:
            print(price)
            if price in orderbook["asks"]:
                del orderbook["asks"][price]
                print(price)
        else:
            orderbook["asks"][price] = quantity
            
            
    orderbook["lastUpdateId"] = u

def updateOrderbook(event):
    global orderbook
    for bid in event["b"]:
        price = float(bid[0])
        quantity = float(bid[1])
        if quantity == 0:
            if price in orderbook["bids"]:
                del orderbook["bids"][price]
        else:
            orderbook["bids"][price] = quantity

    for ask in event["a"]:
        price = float(ask[0])
        quantity = float(ask[1])
        if quantity == 0:
            if price in orderbook["asks"]:
                del orderbook["asks"][price]
        else:
            orderbook["asks"][price] = quantity
    
    orderbook["asks"] = sorted_ordered_dict(orderbook["asks"])
    orderbook["bids"] = sorted_ordered_dict_reverse(orderbook["bids"])

def on_open(ws):
    print("binance websocket open")

def initialize_orderbook(symbol):
    lastUpdateId=None
    lastu=None
    print("lastid"+str(lastUpdateId))

    def on_depth_update(ws, message):
        nonlocal lastUpdateId
        nonlocal lastu
        
        message = json.loads(message)
        event = message["data"]
        # print("U: "+str(event["U"]))
        # print("u: "+str(event["u"]))
        # print("pu: "+str(event["pu"]))

        # # 丢弃 u < lastUpdateId 的部分
        # if event["u"] < lastUpdateId:
        #     return
        # print(lastu)
        # print(event["pu"])
        if lastu!=None and lastu==event["pu"]:
            updateOrderbook(event=event)
            lastu=event["u"]

        # 确保第一个 U <= lastUpdateId 且 u >= lastUpdateId 的事件之后才开始更新订单簿
        if lastUpdateId!=None and event["U"] <= lastUpdateId <= event["u"]:
            print("同步成功")
            updateOrderbook(event=event)
            lastu=event["u"]
            lastUpdateId=None

    # 订阅 WebSocket
    websocket_url = f"wss://fstream.binance.com/stream?streams={symbol.lower()}@depth"
    ws = websocket.WebSocketApp(websocket_url,
                                on_message=on_depth_update,
                                on_open=on_open)
    ws_thread = threading.Thread(target=ws.run_forever,kwargs={"sslopt": {"cert_reqs": ssl.CERT_NONE}})
    ws_thread.start()
    time.sleep(0.5)
    lastUpdateId = get_initial_orderbook(symbol)

def group_order(order):
    grouped_order = defaultdict(float)

    for price, quantity in order.items():
        # 将价格转换为 float 并四舍五入到最近的 0.1 单位
        rounded_price = round(float(price) * 10) / 10
        # 将相同价格区间的数量相加
        grouped_order[rounded_price] =round(grouped_order[rounded_price]+quantity,3)
    # 将 defaultdict 转换为普通字典并打印结果
    grouped_order = dict(grouped_order)
    return grouped_order


def save_snapshoot():
    global orderbook
    while(True):
        time.sleep(1)
        # trading_pair="BTC"
        # current_time = datetime.now().strftime('%Y-%m-%d:%H:%M:%S')
        # trade_data = {
        #     "time": current_time,
        #     "trading_pair": trading_pair,
        #     "buy_order": orderbook["bids"],
        #     "sell_order": orderbook["asks"]
        # }
        # r.set(current_time+"-"+trading_pair+"-BINANCE-Orderbook", json.dumps(trade_data))
        # 获取第一个键值对
        
        # first_key = next(iter(orderbook["asks"]))
        # first_value = orderbook["asks"][first_key]

        # print(f"First key: {first_key}, First value: {first_value}")

        book_buy=group_order(orderbook["bids"])
        book_sell=group_order(orderbook["asks"])
        first_10_items = list(book_buy.items())[:5]

        #first_10_items = list(orderbook["bids"].items())[:5]
        print("买单")
        print(first_10_items)

        first_10_items = list(book_sell.items())[:5]
        #first_10_items = list(orderbook["asks"].items())[:5]
        print("卖单")
        print(first_10_items)

        

        # dict_length = len(orderbook["bids"])
        # last_5_items = list(itertools.islice(orderbook["bids"].items(), dict_length - 5, dict_length))
        # print(last_5_items)
        print("\n")
        

        

if __name__ == "__main__":
    symbol = "ETHUSDT"
    initialize_orderbook(symbol)
    threading.Thread(target=save_snapshoot).start()